package de.slothsoft.wasbinich.core.database.webservice;

import java.io.Serializable;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

import de.slothsoft.wasbinich.core.database.DatabaseException;
import de.slothsoft.wasbinich.core.database.webservice.AbstractOAuth2Authenticator.Token;
import de.slothsoft.wasbinich.core.database.webservice.AbstractOAuth2Authenticator.User;

public class OAuth2Authenticator {

    private static final String BASE_URL = "http://api.slothsoft.de/oauth/v1/"; //$NON-NLS-1$
    private static final String REQUEST_TOKEN_URL = BASE_URL + "token.php"; //$NON-NLS-1$

    private static final String GRANT_TYPE_PASSWORD = "password"; //$NON-NLS-1$
    private static final String GRANT_TYPE_REFRESH_TOKEN = "refresh_token"; //$NON-NLS-1$

    protected static final Gson GSON = new GsonBuilder()
	    .registerTypeAdapter(String[].class, new StringArrayTypeAdapter()).enableComplexMapKeySerialization()
	    .create();
    private RestCommunicator restCommunicator;

    public OAuth2Authenticator(RestCommunicator restCommunicator) {
	this.restCommunicator = restCommunicator;
    }

    public Token getAccessToken(User user) throws DatabaseException {
	System.out.println("OAuth2Authenticator.getAccessToken(" + user.id + ")"); //$NON-NLS-1$ //$NON-NLS-2$
	Map<String, String> parameters = new HashMap<String, String>();
	parameters.put("grant_type", GRANT_TYPE_PASSWORD); //$NON-NLS-1$
	parameters.put("username", user.id); //$NON-NLS-1$
	parameters.put("password", user.password); //$NON-NLS-1$
	return getAccessToken(parameters);
    }

    public Token getAccessToken(String refreshToken) throws DatabaseException {
	System.out.println("OAuth2Authenticator.getAccessToken(" + refreshToken + ")"); //$NON-NLS-1$ //$NON-NLS-2$
	Map<String, String> parameters = new HashMap<String, String>();
	parameters.put("grant_type", GRANT_TYPE_REFRESH_TOKEN); //$NON-NLS-1$
	parameters.put("refresh_token", refreshToken); //$NON-NLS-1$
	return getAccessToken(parameters);
    }

    protected Token getAccessToken(Map<String, String> parameters) throws DatabaseException {
	long currentTime = System.currentTimeMillis();
	JsonToken token = parseResponse(this.restCommunicator.post(REQUEST_TOKEN_URL, parameters), JsonToken.class);
	return new Token(token.access_token, token.refresh_token, new Date(currentTime + token.expires_in * 1000));
    }

    protected <T> T parseResponse(String responseString, Class<T> returnClass) {
	return GSON.fromJson(responseString, returnClass);
    }

    /*
     *
     */

    public static class JsonToken implements Serializable {

	public static final long serialVersionUID = 6404297107770195857L;

	public String access_token;
	public String refresh_token;
	public int expires_in;
	public String token_type;
	public String scope;
    }
}
